/*
 * exame_2010_11_setembro_vsleep.c
 *
 *  Created on: Jun 9, 2012
 *      Author: ubuntu
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>

void fillbuffer(int fp, char *buf, int size);

int main(int argc, char **argv) {
	if (argc < 2) {
		fprintf(stderr, "Usage: %s lista de programas\n", argv[0]);
		exit(EXIT_FAILURE);
	}

	int numeroProgramas = argc - 1;
// variavel para receber os n arrays relaticos ao pipe a criar para cada canal
	int ** pipes = malloc(sizeof(int) * numeroProgramas);

	// 1 se ainda recebe input, 0 se já terminou
	int estadoProgramas[numeroProgramas];

	// inicializacao das estruturas, e criar os pipes
	for (int i = 0; i < numeroProgramas; i++) {
		estadoProgramas[i] = 1;

		int fdreceive[2];
		pipe(fdreceive);
		pipes[i] = fdreceive;
	}

	// bora criar babys, e fazer o devido setup dos pipes
	for (int i = 0; i < numeroProgramas; i++) {
		int pid = fork();

		switch (pid) {
		case -1:
			perror("fork");
			exit(EXIT_FAILURE);

			break;

		case 0: {
			int * fdreceive = pipes[i];

			// estamos interessados em escrever, entao vamos fechar o fd de leitura
			close(fdreceive[0]);

			// mapear o stdout do programa para o fd de escrita
			if (fdreceive[1] != STDOUT_FILENO) {
				dup2(fdreceive[1], STDOUT_FILENO);
			}

			execlp(argv[i + 1], argv[i + 1], NULL);
			perror("execlp");
			exit(EXIT_FAILURE);
			default:
			{
				int * fdreceive = pipes[i];

				// estamos interessados em ler, entao vamos fechar o fd de escrita
				close(fdreceive[1]);
				break;
			}

		}

		}
	} // end for

	// bora ler 10 linhas de cada vez
	for (int indiceLeituraActual = 0; 1 // while true
			; indiceLeituraActual++) {
		if (indiceLeituraActual == numeroProgramas) {
			// deu a volta
			// bora ver se ainda há gajos activos (pelo menos um)
			int flagFilhosActivos = 0;
			for (int i = 0; i < numeroProgramas; i++) {
				if (estadoProgramas[i] == 1) {
					flagFilhosActivos = 1;
					break; // great, we've found one
				}
			}

			if (flagFilhosActivos == 1) {
				// dar a volta ao bicho
				indiceLeituraActual = 0;
			} else {
				// mais nada a fazer
				break;
			}
		}

		if (estadoProgramas[indiceLeituraActual] == 0) {
			// este filho já fechou a loja
			continue;
		}

		printf("Ler linhas do programa %s\n", argv[indiceLeituraActual + 1]);

		int nbytes = 100; // linhas de 100 c deve tar bom
		char * my_string = (char*) malloc(sizeof(char) * (nbytes + 1)); // +1 para o file terminator

		// Ler até 10 linhas
		for (int count = 0; count < 10; count++) {
			// pipes[indiceLeituraActual][0] é o fd de leiura, para o programa indiceLeituraActual
			//puts("fudime");
			//
			//int bytes_read = getline(&my_string, &nbytes,
//					pipes[indiceLeituraActual][0]);
			//puts("?");
			fillbuffer(pipes[indiceLeituraActual][0], my_string, nbytes);

			//if (bytes_read > 0) {
				//puts(my_string);
			//} else {
				//estadoProgramas[indiceLeituraActual] = 0;
			//	break;
			//}
			if (strlen(my_string) > 0) {
				puts(my_string);
			} else {
				estadoProgramas[indiceLeituraActual] = 0;
				break;
			}

		}

	}

}
void fillbuffer(int fp, char *buf, int size) {

	int nbytes, total = 0;
	do {
		// ssize_t read(int fd, void *buf, size_t count);

		// read()  attempts to read up to count bytes from file descriptor fd into
		// the buffer starting at buf.

		nbytes = read(fp, buf + total, size - total);
		// buf + total pq?
		// Ora, como estamos dentro de um ciclo, e não queremos ler sempre para o mesmo sítio,
		// dizemos para escrever a partir do ponto que já escrevemos,
		// ou seja a partir da variavel 'total' que está a registar os bytes lidos.

		total += nbytes;

	} while (0); //while (nbytes > 0 && total < size - 1);
	if (nbytes == -1) { // RETURN VALUE
		// On success, the number of bytes read is returned (zero indicates end of
		// file). On error, -1 is returned, and errno is set
		// appropriately.
		perror("read");
		exit(EXIT_FAILURE);

	}
	size--; // ?

	// colocar o file terminator
	buf[(total < size ? total : size)] = '\0';

	return;
}
